package com.ruoyi.system.service.impl;

import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.system.config.MinioConfig;
import com.ruoyi.system.service.IStandardFileService;
import com.ruoyi.system.utils.Md5Utils;
import io.minio.*;
import io.minio.messages.Item;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.InputStream;

@Service
public class StandardFileService implements IStandardFileService {
    private static final Logger log = LoggerFactory.getLogger(StandardFileService.class);

    @Autowired
    private MinioConfig minioConfig;

    @Autowired
    private MinioClient client;

    /**
     * Minio文件上传接口。
     *
     * @param file 上传的文件。
     * @return the upload result, result[0] means the url, result[1] means the file path.
     * @throws Exception
     */
    @Override
    public String[] uploadFile(MultipartFile file) throws Exception {
        String fileName = FileUploadUtils.extractFilename(file);
        InputStream inputStream = file.getInputStream();
        InputStream md5Stream = file.getInputStream();
        String md5 = Md5Utils.getFileMD5(md5Stream);
        PutObjectArgs args = PutObjectArgs.builder()
                .bucket(minioConfig.getBucketName())
                .object(fileName)
                .stream(inputStream, file.getSize(), -1)
                .contentType(file.getContentType())
                .build();
        client.putObject(args);
        inputStream.close();
        md5Stream.close();
        String url = minioConfig.getReturnUrl() + "/" + minioConfig.getBucketName() + "/" + fileName;
        log.info("upload->{} to {}", file.getOriginalFilename(), url);
        String[] result = new String[3];
        result[0] = url;
        result[1] = fileName;
        result[2] = md5;
        return result;
    }

    /**
     * Minio文件上传接口。
     *
     * @param file 上传的文件。
     * @return 访问地址。
     * @throws Exception
     */
    @Override
    public String[] uploadFileWithFileCode(String fileCode, MultipartFile file) throws Exception {
        String fileName = fileCode;
        InputStream inputStream = file.getInputStream();
        String md5 = Md5Utils.getFileMD5(inputStream);
        PutObjectArgs args = PutObjectArgs.builder()
                .bucket(minioConfig.getBucketName())
                .object(fileName)
                .stream(inputStream, file.getSize(), -1)
                .contentType(file.getContentType())
                .build();
        client.putObject(args);
        inputStream.close();
        String url = minioConfig.getReturnUrl() + "/" + minioConfig.getBucketName() + "/" + fileName;
        log.info("upload->{} to {}", file.getOriginalFilename(), url);

        String[] result = new String[2];
        result[0] = url;
        result[1] = md5;
        return result;
    }

    /**
     * remove file by file path in server.
     *
     * @param filePath the file path in server, the filePath likes: 2023/07/06/blob_20230706112107A003.png
     * @return success or fail.
     */
    @Override
    public String removeFile(String filePath) {
        String flag = "success";
        try {
            log.info("remove file ->{}", filePath);
            RemoveObjectArgs args = RemoveObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    // filePath likes: 2023/07/06/blob_20230706112107A003.png
                    .object(filePath)
                    .build();
            client.removeObject(args);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            flag = "fail";
        }
        return flag;
    }

    /**
     * 判断桶中是否存在文件夹
     *
     * @param bucketName 同名称
     * @param objectName 文件夹名称
     * @param isDeep     是否递归查询(暂不支持)
     * @return
     */
    public Boolean checkBucketFolderExist(String bucketName, String objectName, Boolean isDeep) throws Exception {
        if(checkBucketExist(bucketName)){
            Iterable<Result<Item>> results = client.listObjects(
                    ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(isDeep).build());
            return results.iterator().hasNext(); // 文件夹下存在文件
        }
        return false;
    }

    /**
     * 创建文件夹
     *
     * @param bucketName 桶名
     * @param folderName 文件夹名称
     * @return
     * @throws Exception
     */
    public ObjectWriteResponse createBucketFolder(String bucketName, String folderName) throws Exception {
        if (!checkBucketExist(bucketName)) {
            throw new RuntimeException("必须在桶存在的情况下才能创建文件夹");
        }
        if (!StringUtils.hasLength(folderName)) {
            throw new RuntimeException("创建的文件夹名不能为空");
        }
        PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                .bucket(bucketName)
                .object(folderName + "/")
                .stream(new ByteArrayInputStream(new byte[0]), 0, 0)
                .build();
        return client.putObject(putObjectArgs);
    }

    /**
     * 检查桶是否存在
     *
     * @param bucketName 桶名称
     * @return boolean true-存在 false-不存在
     */
    public boolean checkBucketExist(String bucketName) throws Exception {
        if (!StringUtils.hasLength(bucketName)) {
            throw new RuntimeException("检测桶的时候，桶名不能为空！");
        }
        return client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }

}
